package org.goochasca

private[goochasca] object Chart {
  val URL = "http://chart.apis.google.com/chart?"
  val MaxAxis = 1000
  val MaxArea = 300000
  val EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-."
  val EncodeRange = EncodeChars.length * EncodeChars.length
  def escape(text: String) = java.net.URLEncoder.encode(text, "UTF-8")
}

private[goochasca] abstract class Chart (
  width: Int, height: Int,
  protected val range: Range,
  dataSet: Seq[Data]
) {
  import Chart._

  require(width <= MaxAxis && height <= MaxAxis, "Cannot exceed width or height of "+MaxAxis)
  require(width * height <= MaxArea, String.format("Cannot exceed area of %,d. %dx%d=%,d", int2Integer(MaxArea), int2Integer(width), int2Integer(height), int2Integer(width*height)))
  require(dataSet.size > 0, "Must have at least one data set")
  
  protected val chartType: String
  
  private val valueSet: Float = range.last - range.first + 1
  
  private def appendValue(unscaled: Int, factor: Double, sb: StringBuilder) {
    val value = Math.round(unscaled*factor)
    if (value < range.first || value > range.last)
      sb append "__"
    else {
      val posVal = if (range.first < 0) value-range.first else value
      val scaled = ((posVal/valueSet) * EncodeRange).asInstanceOf[Int]
      val first = scaled / EncodeChars.length
      val second = scaled - first * EncodeChars.length
      sb append EncodeChars.charAt(first)
      sb append EncodeChars.charAt(second)
    }
  }

  protected def appendParms(sb: StringBuilder) {
    sb append "chs=" append width append 'x' append height
    sb append "&cht=" append chartType
    sb append "&chd=e:"
    var first = true
    for (d <- dataSet) {
      if (first) first = false else sb append ','
      for (value <- d.data) appendValue(value, d.multiplier, sb)
    }
  }

  override final def toString = {
    val sb = new StringBuilder(URL)
    appendParms(sb)
    sb.toString
  }
  
  def toURL = new java.net.URL(toString)
}


//abstract class BarChart (w: Int, h: Int, d: DataSet*) extends Chart(w, h, d: _*)
//abstract class PieChart (w: Int, h: Int, d: DataSet*) extends Chart(w, h, d: _*)
//abstract class VennDiagram (w: Int, h: Int, d: DataSet*) extends Chart(w, h, d: _*)
//abstract class ScatterPlot (w: Int, h: Int, d: DataSet*) extends Chart(w, h, d: _*)
//abstract class RadarChart (w: Int, h: Int, d: DataSet*) extends Chart(w, h, d: _*)
